package network

import (
	"net"
	"sync"
)

type ConnId struct {
	Index  int
	Serial int
}

type ClientConn struct {
	id        int
	conn      net.Conn
	sendqueue chan []byte
	quit      chan bool
}

type ConnPool struct {
	serial   int
	pl       sync.RWMutex
	capacity int
	cl       []ClientConn
}

func (cp *ConnPool) Add(conn net.Conn) ConnId {
	cp.pl.Lock()
	defer cp.pl.Unlock()
	cp.serial++
	if cp.serial <= 0 {
		cp.serial = 1
	}

	for i := 0; i < cp.capacity; i++ {
		if cp.cl[i].id == 0 {
			cp.cl[i].id = cp.serial
			cp.cl[i].conn = conn
			cp.cl[i].sendqueue = make(chan []byte, 10)
			cp.cl[i].quit = make(chan bool)
			return ConnId{i, cp.cl[i].id}
		}
	}

	return ConnId{}
}

func (cp *ConnPool) Remove(c ConnId) bool {
	cp.pl.Lock()
	defer cp.pl.Unlock()

	if c.Index >= cp.capacity {
		return false
	}

	if cp.cl[c.Index].id != c.Serial {
		return false
	}

	cp.cl[c.Index].id = 0
	cp.cl[c.Index].conn = nil
	cp.cl[c.Index].sendqueue = nil
	cp.cl[c.Index].quit = nil
	return true
}

func (cp *ConnPool) GetConn(c ConnId) net.Conn {
	cp.pl.RLock()
	defer cp.pl.RUnlock()

	if c.Index >= cp.capacity {
		return nil
	}

	if cp.cl[c.Index].id != c.Serial {
		return nil
	}

	return cp.cl[c.Index].conn
}

func (cp *ConnPool) Get(c ConnId) *ClientConn {
	cp.pl.RLock()
	defer cp.pl.RUnlock()

	if c.Index >= cp.capacity {
		return nil
	}

	if cp.cl[c.Index].id != c.Serial {
		return nil
	}

	return &cp.cl[c.Index]
}

func NewPool(capacity int) *ConnPool {
	cp := &ConnPool{}
	cp.capacity = capacity
	cp.cl = make([]ClientConn, capacity, capacity)
	return cp
}

type SvrSockCallee interface {
	OnAccept(id ConnId, addr net.Addr)
	OnClose(id ConnId, addr net.Addr)
	OnReceive(id ConnId, data []byte)
}

type SvrSock struct {
	lister net.Listener
	cp     *ConnPool
	callee SvrSockCallee
	buflen int
}

func (s *SvrSock) accept() {
	for {
		conn, err := s.lister.Accept()
		if err != nil {
			break
		} else {
			//fmt.Println(conn)
			cid := s.cp.Add(conn)
			if cid.Serial == 0 {
				conn.Close()
				continue
			}

			clientHandler(s, cid)
		}
	}
}

func (s *SvrSock) Shutdown() {
	s.lister.Close()
	s.CloseAll()
}

func (s *SvrSock) CloseAll() {
	s.cp.pl.RLock()
	defer s.cp.pl.RUnlock()

	for i := 0; i < s.cp.capacity; i++ {
		if s.cp.cl[i].conn == nil {
			continue
		}

		s.cp.cl[i].conn.Close()
	}
}

func (s *SvrSock) Listen(addr net.Addr, threads int) error {

	lister, err := net.Listen("tcp", addr.String())
	if err != nil {
		return err
	} else {
		s.lister = lister
		for i := 0; i < threads; i++ {
			go s.accept()
		}
	}

	return nil
}

func (s *SvrSock) CloseConn(id ConnId) bool {
	cc := s.cp.Get(id)
	if cc == nil {
		return false
	}
	s.callee.OnClose(id, cc.conn.RemoteAddr())
	cc.quit <- true
	cc.conn.Close()
	s.cp.Remove(id)
	return true
}

func (s *SvrSock) Send(id ConnId, data []byte) bool {
	cc := s.cp.Get(id)
	if cc == nil {
		return false
	}

	cc.sendqueue <- data

	return true
}

func (s *SvrSock) Broadcast(data []byte) {
	s.cp.pl.RLock()
	defer s.cp.pl.RUnlock()
	for i := 0; i < s.cp.capacity; i++ {
		if s.cp.cl[i].conn != nil {
			s.cp.cl[i].sendqueue <- data
		}
	}
}

func NewSvrSock(callee SvrSockCallee, recvbuflen int, maxclient int) *SvrSock {
	sc := &SvrSock{}
	sc.callee = callee
	sc.buflen = recvbuflen
	sc.cp = NewPool(maxclient)
	return sc
}

func clientHandler(server *SvrSock, cid ConnId) {
	cc := server.cp.Get(cid)
	server.callee.OnAccept(cid, cc.conn.RemoteAddr())
	go clientReader(server, cid, cc)
	go clientSend(server, cid, cc)
}

//读进程(每个socket一个)
func clientReader(server *SvrSock, cid ConnId, cc *ClientConn) {
	b := make([]byte, server.buflen)
	for {
		count, err := cc.conn.Read(b)
		if err != nil {
			server.CloseConn(cid)
			break
		}

		server.callee.OnReceive(cid, b[:count])
	}
}

func clientSend(server *SvrSock, cid ConnId, cc *ClientConn) {
loop:
	for {
		select {
		case data := <-cc.sendqueue:
			cc.conn.Write(data)
		case <-cc.quit:
			break loop
		}
	}
}
